package fpc.changers;
import flash.utils.TypedDictionary;

class Changer< T >
{	
	public function new(listener:T->Dynamic = null)
	{
		_level = 0;
		_listeners = [];
		if (listener != null)
		{
			add(listener);
		}
	}
	
	var _listeners:Array < T->Dynamic > ;
	
	var _collective:TypedDictionary< Changer < T >, Changer< T >>;
	
	public function linkTo(changer:Changer<T>):Changer<T>
	{
		if (_collective == null)
		{
			if (changer._collective == null)
			{
				var changers = new TypedDictionary< Changer < T >, Changer< T >>();
				changers.set(this, this);
				changers.set(changer, changer);
				_collective = changer._collective = changers;
			}
			else
			{
				(_collective = changer._collective).set(this, this);
			}
		}
		else
		{
			if (changer._collective == null)
			{
				(changer._collective = _collective).set(changer, changer);
			}
			else
			{
				var newCollective = changer._collective;
				for (i in _collective)
				{
					newCollective.set(i, i);
					i._collective = newCollective;
				}
				_collective = newCollective;
			}
		}
		return this;
	}
	
	public function unlink()
	{
		if (_collective != null)
		{
			_collective.delete(this);
			_collective = null;
		}
	}
	
	public function add(setValue:T->Dynamic)
	{
		remove(setValue);
		_listeners.push(setValue);
		return setValue;
	}
	
	var _level:Int;
	
	public var value(getValue, setValue):T;
	var _value:T;
	function getValue()
	{
		return _value;
	}
	function setValue(value:T)
	{
		/*
		if (value == _value)
		{
			return value;
		}
		*/
		
		_value = value;
		
		if (_level == 0)
		{	
			_level++;
			if (_collective != null)
			{
				for (changer in _collective)
				{
					changer._level++;
					changer._value = _value;
					for (listener in changer._listeners)
					{
						listener(_value);
					}
					changer._level--;
				}
			} 
			else
			{
				for (listener in _listeners)
				{
					listener(_value);
				}
			}
			_level--;
		}
		return value;
	}
	
	public function remove(setValue:T->Dynamic)
	{
		_listeners.remove(setValue);
	}
}